﻿using System;
using System.IO;
using System.Threading;

namespace CommonEngine.Helper
{
    /// <summary>
    /// 文件日志记录
    /// </summary>
    public sealed class FileLogHelper
    {
        private readonly string _fileName;
        //读写锁，当资源处于写入模式时，其他线程写入需要等待本次写入结束之后才能继续写入
        private static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();

        /// <summary>  
        /// 获取或设置文件名称  
        /// </summary>  
        public string FileName
        {
            get { return this._fileName; }
        }

        /// <summary>  
        /// 构造函数  
        /// </summary>
        internal FileLogHelper(string FilePath)
        {
            if (string.IsNullOrEmpty(FilePath))
                FilePath = CommonOP.LogPath();

            this._fileName = FilePath + "FLog" + CommonOP.GetIntByDT(DateTime.Today).ToString() + ".txt";
            this.Create(this._fileName);
        }

        /// <summary>  
        /// 创建文件  
        /// </summary>
        private void Create(string fileName)
        {
            if (!System.IO.File.Exists(fileName))
            {
                using (System.IO.FileStream fs = System.IO.File.Create(fileName))
                {
                    fs.Close();
                }
            }
        }

        /// <summary>  
        /// 写入文本  
        /// </summary>  
        /// <param name="content">文本内容</param>  
        private void Write(string content, string newLine)
        {
            if (string.IsNullOrEmpty(this._fileName))
            {
                throw new Exception("FileName不能为空！");
            }

            try
            {
                //设置读写锁为写入模式独占资源，其他写入请求需要等待本次写入结束之后才能继续写入
                //注意：长时间持有读线程锁或写线程锁会使其他线程发生饥饿 (starve)。 为了得到最好的性能，需要考虑重新构造应用程序以将写访问的持续时间减少到最小。
                //      从性能方面考虑，请求进入写入模式应该紧跟文件操作之前，在此处进入写入模式仅是为了降低代码复杂度
                //      因进入与退出写入模式应在同一个try finally语句块内，所以在请求进入写入模式之前不能触发异常，否则释放次数大于请求次数将会触发异常
                LogWriteLock.EnterWriteLock();
                File.AppendAllText(this._fileName, content + newLine);
            }
            catch (Exception)
            {
                throw new Exception("写入失败！");
            }
            finally
            {
                //退出写入模式，释放资源占用
                //注意：一次请求对应一次释放
                //      若释放次数大于请求次数将会触发异常[写入锁定未经保持即被释放]
                //      若请求处理完成后未释放将会触发异常[此模式不下允许以递归方式获取写入锁定]
                LogWriteLock.ExitWriteLock();
            }
        }

        /// <summary>
        /// 写入文件内容  
        /// </summary>
        public void WriteLine(string content)
        {
            this.Write(content, Environment.NewLine);
        }

        /// <summary>  
        /// 写入文件  
        /// </summary>
        public void Write(string content)
        {
            this.Write(content, string.Empty);
        }
    }
}
